package api

import (
	"a_plus_station/dto_out"
	"a_plus_station/forms"
	"a_plus_station/global"
	"a_plus_station/middlewares"
	"a_plus_station/models"
	vali_tran "a_plus_station/validator"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	"github.com/olivere/elastic/v7"
	"go.uber.org/zap"
	"net/http"
	"reflect"
	"regexp"
	"strings"
	"time"
)

//
//import (
//	"a_plus_station/dto_out"
//	"a_plus_station/forms"
//	"a_plus_station/global"
//	"a_plus_station/tables"
//	vali_tran "a_plus_station/validator"
//	"fmt"
//	"github.com/gin-gonic/gin"
//	"github.com/google/uuid"
//	"go.uber.org/zap"
//	"net/http"
//	"path/filepath"
//	"regexp"
//	"strconv"
//	"strings"
//)
//
//// api 具体的内部逻辑
//func FoodList(ctx *gin.Context) {
//	categoryID := ctx.DefaultQuery("categoryID", "")
//	cI, _ := strconv.Atoi(categoryID)
//	var tc tables.Category
//
//	tx := global.DB.WithContext(ctx).Model(&tables.Food{})
//	if cI != 0 {
//		tc.ID = int32(cI)
//		result := tc.CategoryExist(ctx)
//		if result.RowsAffected == 0 {
//			zap.S().Infof("%s 分类不存在", result.Error)
//			ctx.JSON(http.StatusBadRequest, gin.H{
//				"msg": "分类不存在",
//			})
//			return
//		}
//		tx = tx.Where(&tables.Food{CategoryId: int32(cI)})
//	}
//
//	var foods []tables.Food
//	result := tx.Find(&foods)
//	if result.Error != nil {
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "获取食物失败",
//		})
//		return
//	}
//
//	var foodLi []dto_out.FoodLiInfo
//	for _, fo := range foods {
//		range_food := dto_out.FoodLiInfo{
//			ID:         fo.ID,
//			CreateAt:   fo.CreatedAt.Format("2006-01-02 15:04:15"),
//			Name:       fo.Name,
//			Price:      fo.Price,
//			Image:      fo.Image[0],
//			CategoryId: fo.CategoryId,
//			Desc:       fo.Desc,
//		}
//		foodLi = append(foodLi, range_food)
//	}
//	if foodLi == nil {
//		foodLi = make([]dto_out.FoodLiInfo, 0)
//	}
//	foodOut := dto_out.FoodLiOut{
//		FoodInfo: foodLi,
//		Count:    int64(len(foodLi)),
//	}
//	// 返回
//	ctx.JSON(http.StatusOK, gin.H{
//		"status": 200,
//		"data":   foodOut,
//		"msg":    "获取食物列表成功",
//	})
//	return
//}
//
//func isImgFormat(filetype string) bool {
//	format := `^(\.(png|jpg|jpeg|bmp|tif))$`
//	ok, _ := regexp.MatchString(format, filetype)
//	return ok
//}
//
//func FoodCreate(ctx *gin.Context) {
//	var foodCreate forms.FoodCreate
//	zap.S().Debugf("删除分类%v", foodCreate)
//	err := ctx.ShouldBind(&foodCreate)
//	if err != nil {
//		vali_tran.HandleValidatorError(ctx, err)
//		return
//	}
//
//	fileForm, err := ctx.MultipartForm()
//	if err != nil {
//		zap.S().Infof("%s 文件上传错误", err.Error())
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "文件上传错误",
//		})
//		return
//	}
//	files := fileForm.File["files"]
//	if files == nil {
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "必须上传食物图片",
//		})
//		return
//	}
//
//	tc := tables.Category{
//		BaseModel: tables.BaseModel{ID: foodCreate.CategoryId},
//	}
//	result := tc.CategoryExist(ctx)
//	if result.RowsAffected == 0 {
//		zap.S().Infof("%s 分类已存在", result.Error)
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "分类不存在",
//		})
//		return
//	}
//
//	images := make([]string, 0)
//	for _, file := range files {
//		fileDot := strings.Index(file.Filename, ".")
//		fileType := file.Filename[fileDot:]
//		ok := isImgFormat(fileType)
//		if !ok {
//			ctx.JSON(http.StatusBadRequest, gin.H{
//				"msg": "文件类型上传错误: png|jpg|jpeg|bmp|tif",
//			})
//			return
//		}
//
//		u4 := uuid.New()
//		uid := u4.String()
//		filename := filepath.Join(fmt.Sprintf("%s-%s%s", foodCreate.Name, uid, fileType))
//		err = ctx.SaveUploadedFile(file, filepath.Join(global.ServerConfig.Image, filename))
//		if err != nil {
//			ctx.JSON(http.StatusBadRequest, gin.H{
//				"msg": "文件保存失败",
//			})
//			return
//		}
//		images = append(images, global.ServerConfig.Image+"/"+filename)
//	}
//
//	tx := global.DB.Begin()
//	food := tables.Food{
//		Name:       foodCreate.Name,
//		Image:      images,
//		Price:      foodCreate.Price,
//		Desc:       foodCreate.Desc,
//		CategoryId: foodCreate.CategoryId,
//	}
//	result = tx.WithContext(ctx).Model(&tables.Food{}).Create(&food)
//	if result.Error != nil {
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "食物创建失败",
//		})
//		tx.Rollback()
//		return
//	}
//	tx.Commit()
//
//	fo := dto_out.FoodInfo{
//		ID:         food.ID,
//		CreateAt:   food.CreatedAt.Format("2006-01-02 15:04:05"),
//		Name:       food.Name,
//		Price:      food.Price,
//		Image:      food.Image,
//		CategoryId: food.CategoryId,
//		Desc:       food.Desc,
//	}
//	ctx.JSON(http.StatusOK, gin.H{
//		"status": 200,
//		"data":   fo,
//		"msg":    "食物创建成功",
//	})
//	return
//}
//
//func FoodDelete(ctx *gin.Context) {
//	var foodDelete forms.FoodDelete
//	zap.S().Debugf("删除食物%v", foodDelete)
//	err := ctx.ShouldBind(&foodDelete)
//	if err != nil {
//		vali_tran.HandleValidatorError(ctx, err)
//		return
//	}
//
//	tx := global.DB.Begin()
//	tc := tables.Food{
//		BaseModel: tables.BaseModel{ID: foodDelete.ID},
//	}
//	result := tx.WithContext(ctx).Delete(&tc)
//	if result.Error != nil {
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "食物删除失败",
//		})
//		tx.Rollback()
//		return
//	}
//	tx.Commit()
//
//	ctx.JSON(http.StatusOK, gin.H{
//		"status": 200,
//		"data":   foodDelete.ID,
//		"msg":    "创建分类成功",
//	})
//	return
//}
//
//func FoodDesc(ctx *gin.Context) {
//
//	foodID := ctx.Param("id")
//	fId, _ := strconv.Atoi(foodID)
//	food := tables.Food{
//		BaseModel: tables.BaseModel{ID: int32(fId)},
//	}
//
//	result := global.DB.WithContext(ctx).Find(&food)
//	if result.RowsAffected == 0 {
//		ctx.JSON(http.StatusBadRequest, gin.H{
//			"msg": "获取食物详情失败",
//		})
//		return
//	}
//
//	fo := dto_out.FoodInfo{
//		ID:         food.ID,
//		CreateAt:   food.CreatedAt.Format("2006-01-02 15:04:05"),
//		Name:       food.Name,
//		Price:      food.Price,
//		Image:      food.Image,
//		CategoryId: food.CategoryId,
//		Desc:       food.Desc,
//	}
//
//	ctx.JSON(http.StatusOK, gin.H{
//		"status": 200,
//		"data":   fo,
//		"msg":    "创建分类成功",
//	})
//	return
//}

func in(target string, strArray []string) bool {
	for _, element := range strArray {
		if target == element {
			return true
		}
	}
	return false
}

func SearchKeyWordsFormat(search string) string {
	// 替换
	reg := regexp.MustCompile(`[^a-zA-Z0-9]+`)
	clean := reg.ReplaceAllString(search, " ")
	// 去除多余的空格
	fields := strings.Fields(clean)
	output := strings.Join(fields, " ")

	return output
}

func GoodsList(ctx *gin.Context) {
	goodsSearchForm := forms.GoodsSearch{}
	err := ctx.ShouldBind(&goodsSearchForm)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}

	if goodsSearchForm.SortField != "" {
		fieldIsIn := in(goodsSearchForm.SortField, []string{"shop_min_price", "shop_max_price", "created_at", "click", "score", "is_new", "is_hot"})
		if !fieldIsIn {
			zap.S().Infof("%s 排序字段无效", goodsSearchForm.SortField)
			ctx.JSON(http.StatusBadRequest, gin.H{
				"msg": "排序字段无效",
			})
			return
		}
	}

	q := elastic.NewBoolQuery()
	if goodsSearchForm.KeyWords != "" {
		KeyWords := SearchKeyWordsFormat(goodsSearchForm.KeyWords)
		zap.S().Infof("%s 搜索关键词", KeyWords)
		q = q.Must(elastic.NewMultiMatchQuery(KeyWords, "name", "key_words", "goods_desc", "goods_id"))
	}

	if goodsSearchForm.CategoryID > 0 {
		q = q.Filter(elastic.NewTermQuery("category_id", goodsSearchForm.CategoryID))
	}

	if goodsSearchForm.ShopMinPrice > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_min_price").Gte(goodsSearchForm.ShopMinPrice))
	}

	if goodsSearchForm.ShopMaxPrice > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_max_price").Lte(goodsSearchForm.ShopMaxPrice))
	}

	zap.S().Infof("%s es搜索", q)

	switch {
	case goodsSearchForm.Page <= 0:
		goodsSearchForm.Page = 1
	case goodsSearchForm.Page >= 999:
		goodsSearchForm.Page = 999
	}

	switch {
	case goodsSearchForm.PageSize > 28:
		goodsSearchForm.PageSize = 28
	case goodsSearchForm.PageSize <= 0:
		goodsSearchForm.PageSize = 28
	}

	offset := (goodsSearchForm.Page - 1) * goodsSearchForm.PageSize

	esSearch := global.EsClient.Search().Index(models.EsGoods{}.GetIndexName()).Query(q)
	if goodsSearchForm.SortField == "" {
		esSearch = esSearch.Sort("created_at", false) // false 降序
	} else {
		esSearch = esSearch.Sort(goodsSearchForm.SortField, goodsSearchForm.Sort)
	}

	re, err := esSearch.Sort("created_at", false).From(int(offset)).Size(int(goodsSearchForm.PageSize)).Do(ctx)
	if err != nil {
		zap.S().Infof("%s es错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es错误",
		})
		return
	}

	src, err := q.Source()
	if err != nil {
		zap.S().Infof("%s es查询错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es查询错误",
		})
		return
	}
	data, err := jsoniter.MarshalIndent(src, "", "  ")
	if err != nil {
		zap.S().Infof("%s es序列化错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es序列化错误",
		})
		return
	}
	zap.S().Infof("%s es搜索", string(data))

	total := int32(re.Hits.TotalHits.Value)
	zap.S().Infof("%d es搜索 共计:", total)

	var goodsLi []dto_out.GoodsLiInfo
	for _, v := range re.Hits.Hits {
		goods := models.EsGoods{}
		jsoniter.Unmarshal(v.Source, &goods)
		goodsLiInfo := dto_out.GoodsLiInfo{
			GoodsID:      goods.GoodsID,
			Name:         goods.Name,
			GoodsDesc:    goods.GoodsDesc,
			Score:        goods.Score,
			ShopMinPrice: goods.ShopMinPrice,
			ShopMaxPrice: goods.ShopMaxPrice,
			MainPicture:  goods.MainPicture,
			CreateAt:     goods.CreatedAt,
		}
		goodsLi = append(goodsLi, goodsLiInfo)
	}

	GoodsOut := dto_out.GoodsLiOut{
		GoodsLiInfo: goodsLi,
		Count:       total,
	}
	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "es查询成功",
		"data":   GoodsOut,
		"status": 200,
	})
	return
}

func GoodsDesc(ctx *gin.Context) {
	var userIdInt int32
	token := ctx.Request.Header.Get("token")
	if token != "" {
		j := middlewares.NewJWT()
		// parseToken 解析token包含的信息
		claims, err := j.ParseToken(token)
		if err == nil {
			userIdInt = claims.ID
		}
	}

	goodsId := ctx.Param("id")
	if goodsId == "" {
		ctx.Status(http.StatusNotFound)
		return
	}

	// 设置查询条件
	query := elastic.NewTermQuery("goods_id", goodsId)

	// 执行查询
	searchResult, err := global.EsClient.Search().
		Index("goods"). // 设置索引名称
		Query(query).   // 设置查询条件
		Do(ctx)         // 执行查询
	if err != nil {
		zap.S().Infof("%s es序列化错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es查询出错",
		})
		return
	}

	// 处理查询结果
	var goods models.EsGoods
	for _, item := range searchResult.Each(reflect.TypeOf(goods)) {
		if g, ok := item.(models.EsGoods); ok {
			gImsges := g.Image
			for i, j := 0, len(gImsges)-1; i < j; i, j = i+1, j-1 {
				gImsges[i], gImsges[j] = gImsges[j], gImsges[i] // 交换元素
			}
			if userIdInt == 0 {
				ctx.JSON(http.StatusOK, gin.H{
					"msg": "es查询成功",
					"data": map[string]interface{}{
						"goodsDesc": g,
						"collect":   false,
					},
					"status": 200,
				})
			} else {
				collected, err := global.CollectCache.IsCollected(userIdInt, g.GoodsID)
				if err != nil {
					zap.S().Infof("%s 收藏查询失败", g.GoodsID)
					ctx.JSON(http.StatusInternalServerError, gin.H{
						"msg": "收藏查询失败",
					})
					return
				}
				ctx.JSON(http.StatusOK, gin.H{
					"msg": "es查询成功",
					"data": map[string]interface{}{
						"goodsDesc": g,
						"collect":   collected,
					},
					"status": 200,
				})
			}
			return
		}
	}
	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "es查询失败",
		"data":   map[string]string{},
		"status": 200,
	})
	return
}

func queryGoods(ctx *gin.Context, categoryID *int32, field string, size int) ([]dto_out.GoodsLiInfo, error) {
	var query elastic.Query
	if categoryID == nil || *categoryID == 0 {
		// CategoryID 为 nil 或 0 时，不添加分类条件
		query = elastic.NewBoolQuery().Must(elastic.NewTermQuery(field, 1))
	} else {
		// CategoryID 不为 nil 且不为 0 时，添加分类条件
		query = elastic.NewBoolQuery().Must(elastic.NewTermQuery("category_id", *categoryID)).Must(elastic.NewTermQuery(field, 1))
	}

	functionScoreQ := elastic.NewFunctionScoreQuery().Query(query).AddScoreFunc(elastic.NewRandomFunction().Seed(time.Now().UnixNano()))

	searchResult, err := global.EsClient.Search().Index(models.EsGoods{}.GetIndexName()).Query(functionScoreQ).Size(size).Do(ctx)

	if err != nil {
		return nil, err
	}

	var goodsLi []dto_out.GoodsLiInfo
	for _, hit := range searchResult.Hits.Hits {
		goods := models.EsGoods{}
		err := jsoniter.Unmarshal(hit.Source, &goods)
		if err != nil {
			return nil, err
		}
		goodsLiInfo := dto_out.GoodsLiInfo{
			GoodsID:      goods.GoodsID,
			Name:         goods.Name,
			GoodsDesc:    goods.GoodsDesc,
			Score:        goods.Score,
			ShopMinPrice: goods.ShopMinPrice,
			ShopMaxPrice: goods.ShopMaxPrice,
			MainPicture:  goods.MainPicture,
			CreateAt:     goods.CreatedAt,
		}
		goodsLi = append(goodsLi, goodsLiInfo)
	}

	return goodsLi, nil
}

func chunkSlice(slice []dto_out.GoodsLiInfo, chunkSize int) [][]dto_out.GoodsLiInfo {
	var dividedSlice [][]dto_out.GoodsLiInfo

	for i := 0; i < len(slice); i += chunkSize {
		end := i + chunkSize

		if end > len(slice) {
			end = len(slice)
		}

		dividedSlice = append(dividedSlice, slice[i:end])
	}

	return dividedSlice
}

func GoodsRandom(ctx *gin.Context) {
	goodsRandom := forms.GoodsRandom{}
	err := ctx.ShouldBind(&goodsRandom)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}

	field := ""
	if goodsRandom.IsNew == 1 {
		field = "is_new"
	} else {
		field = "is_hot"
	}

	size := 0
	if goodsRandom.Size >= 16 || goodsRandom.Size <= 0 {
		size = 16
	} else {
		size = goodsRandom.Size
	}

	hotGoods, err := queryGoods(ctx, goodsRandom.CategoryID, field, size)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es查询失败",
		})
		return
	}

	split := 0
	if goodsRandom.Split >= 6 || goodsRandom.Split <= 0 {
		split = 6
	} else {
		split = goodsRandom.Split
	}

	chunkedSlice := chunkSlice(hotGoods, split)

	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "es查询成功",
		"data":   chunkedSlice,
		"status": 200,
	})
	return
}

// 获取详情
//var goodsLi []dto_out.GoodsInfo
//	for _, v := range re.Hits.Hits {
//		goods := models.EsGoods{}
//		jsoniter.Unmarshal(v.Source, &goods)
//		goodsLiInfo := dto_out.GoodsInfo{
//			GoodsID:      goods.GoodsID,
//			CategoryID:   goods.CategoryID,
//			Name:         goods.Name,
//			GoodsDesc:    goods.GoodsDesc,
//			Click:        goods.Click,
//			Score:        goods.Score,
//			ShopMinPrice: goods.ShopMinPrice,
//			ShopMaxPrice: goods.ShopMaxPrice,
//			PackingMode:  goods.PackingMode,
//			LeadTime:     goods.LeadTime,
//			DeliveryTime: goods.DeliveryTime,
//			MainPicture:  goods.MainPicture,
//			CreateAt:     goods.CreatedAt,
//			ISNew:        goods.IsNew,
//			ISHot:        goods.ISHot,
//			KeyWords:     goods.KeyWords,
//		}
//		goodsLi = append(goodsLi, goodsLiInfo)
//	}
//
//	GoodsOut := dto_out.GoodsLiOut{
//		GoodsLiInfo: goodsLi,
//		Count:       total,
//	}
